/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package pokergame;

import java.io.Serializable;

/**
 *
 * @author Justin
 */
public class Hand implements Serializable, Comparable<Hand>
{

    Card[] cards;
    private int[] value;

    Hand(Deck d)
    {
        value = new int[6];
        cards = new Card[2];
        for (int x = 0; x < 2; x++)
        {
            cards[x] = d.Draw();
            d.Draw();
        }
    }

    /**
     * for other objects, like the gui, to get the cards in the hand.
     *
     * @return an array of the cards held inside this object.
     */
    public void Evaluate(Board b)
    {
        Card[] fullHand = new Card[7];
        for (int i = 0; i < 2; ++i)
        {
            fullHand[i] = cards[i];
        }

        for (int i = 0; i < 5; ++i)
        {
            fullHand[i + 2] = b.cards[i];
        }

        int[] ranks = new int[14];
        int[] suits = new int[4]; //0-heart, 1-diamond, 2-club, 3-spade

        for (int x = 0; x < 7; x++)
        {
            ranks[ fullHand[x].GetRank().ordinal()]++; //increment rank array at the index of each card's rank
            suits[ fullHand[x].GetSuit().ordinal()]++; //track number of each suit
        }

        int sameCards = 1, sameCards2 = 1;			//initialze to 1
        int largeGroupRank = 0, smallGroupRank = 0;

        // look for 2, 3, 4 of a kinds or a full house
        for (int x = 13; x > 0; --x)
        {
            if (ranks[x] > sameCards)
            {
                if (sameCards != 1)  //if sameCards was not the default value
                {
                    sameCards2 = sameCards;
                    smallGroupRank = x;
                }

                sameCards = ranks[x];
                largeGroupRank = x;
            } else
            {
                if (ranks[x] > sameCards2)
                {
                    sameCards2 = ranks[x];
                    smallGroupRank = x;
                }
            }
        }

        boolean flush = false;
        Card.Suit flushSuit;
        // if three cards are not of the same suit, then can't have flush
        for (int i = 0; i < 4; ++i)
        {
            if (suits[i] == 5)
            {
                flush = true;
                flushSuit = Card.Suit.values()[i];
            }
        }

        int straightValue = 0;
        boolean straight = false;
        // check for straight
        for (int i = 1; i < 8; ++i)
        {
            if (ranks[i] >= 1 && ranks[i + 1] >= 1 && ranks[i + 2] >= 1 && ranks[i + 3] >= 1 && ranks[i + 4] >= 1)
            {
                straight = true;
                straightValue = i + 4;
                break;
            }
        }
        // check for ace high straight


        // only single cards
        int[] orderedRanks = new int[7];
        int index = 0;



        for (int i = 13; i >= 0; --i)
        {
            if (ranks[i] == 1)
            {
                orderedRanks[index] = i;
                index++;
            }
        }

//start hand evaluation
        if (sameCards == 1)
        {	//if we have no pair
            value[0] = 1;		  //this is the lowest type of hand, so it gets the lowest value
            value[1] = orderedRanks[0];  //the first determining factor is the highest card,
            value[2] = orderedRanks[1];  //then the next highest card,
            value[3] = orderedRanks[2];  //and so on
            value[4] = orderedRanks[3];
            value[5] = orderedRanks[4];
        }

        if (sameCards == 2 && sameCards2 == 1) //if 1 pair
        {
            value[0] = 2;                 //pair ranked higher than high card
            value[1] = largeGroupRank;    //rank of pair
            value[2] = orderedRanks[0];   //next highest cards.
            value[3] = orderedRanks[1];
            value[4] = orderedRanks[2];
        }

        if (sameCards == 2 && sameCards2 == 2) //two pair
        {
            value[0] = 3;
            value[1] = largeGroupRank > smallGroupRank ? largeGroupRank : smallGroupRank; //rank of greater pair
            value[2] = largeGroupRank < smallGroupRank ? largeGroupRank : smallGroupRank; //rank of smaller pair
            value[3] = orderedRanks[0];  //extra card
        }

        if (sameCards == 3 && sameCards2 != 2) //three of a kind (not full house)
        {
            value[0] = 4;
            value[1] = largeGroupRank;
            value[2] = orderedRanks[0];
            value[3] = orderedRanks[1];
        }

        if (straight)
        {
            value[0] = 5;
            value[1] = straightValue; //if we have two straights, the one with the highest top cards wins
        }

        if (flush)
        {
            value[0] = 6;
            value[1] = orderedRanks[0]; //tie determined by ranks of cards
            value[2] = orderedRanks[1];
            value[3] = orderedRanks[2];
            value[4] = orderedRanks[3];
            value[5] = orderedRanks[4];
        }

        if (sameCards == 3 && sameCards2 == 2)  //full house
        {
            value[0] = 7;
            value[1] = largeGroupRank;
            value[2] = smallGroupRank;
        }

        if (sameCards == 4)  //four of a kind
        {
            value[0] = 8;
            value[1] = largeGroupRank;
            value[2] = orderedRanks[0];
        }

        if (straight && flush)  //straight flush
        {
            value[0] = 9;
            value[1] = straightValue;
        }
    }

    public String ValueOf()
    {
        String s = "";
        switch (value[0])
        {
            case 1:
                s = "high card";
                break;
            case 2:
                s = "pair of " + "\'s";
                break;
            case 3:
                s = "two pair " + Card.Rank.values()[value[1]] + " + " + Card.Rank.values()[value[2]];
                break;
            case 4:
                s = "three of a kind " + Card.Rank.values()[value[1]] + "\'s";
                break;
            case 5:
                s = Card.Rank.values()[value[1]] + " high straight";
                break;
            case 6:
                s = "flush";
                break;
            case 7:
                s = "full house " + Card.Rank.values()[value[1]] + " over " + Card.Rank.values()[value[2]];
                break;
            case 8:
                s = "four of a kind " + Card.Rank.values()[value[1]];
                break;
            case 9:
                s = "straight flush " + Card.Rank.values()[value[1]] + " high";
                break;
            default:
                s = "error in Hand.valueof: value[0] contains invalid value";
        }
        return s;
    }

    public int StrengthOf()
    {
        return value[0];
    }

    public @Override
    String toString()
    {
        String s = "";
        for (int i = 0; i < 2; ++i)
        {
            s += cards[i] + ", ";
        }
        return s;
    }

    @Override
    public int compareTo(Hand that)
    {
        for (int i = 0; i < 6; ++i)
        {
            if (this.value[i] < that.value[i])
            {
                return 1;
            } else
            {
                if (this.value[i] > that.value[i])
                {
                    return -1;
                }
            }
        }
        return 0; // hands are equal, draw
    }
}
